package mail

import (
	"errors"
	"fmt"
	"math/rand"
	"reflect"
	"runtime"
	"strings"
	"time"
)

func RecoverPanic(fixer ...func(err interface{})) {
	if err := recover(); err != nil {
		stacks := GetStacks()
		fmt.Printf("err: %s, stacks: %s", err, stacks)
		if len(fixer) > 0 {
			fixer[0](err)
		}
	}
}

func GetStacks() string {
	var stack []string
	for i := 1; ; i++ {
		_, file, line, ok := runtime.Caller(i)
		if !ok {
			break
		}
		stack = append(stack, fmt.Sprintf("%s:%d", file, line))
	}
	return strings.Join(stack, "\r\n")
}

func IfStr(cond bool, a, b string) string {
	if cond {
		return a
	}
	return b
}

func IfInt(cond bool, a, b int) int {
	if cond {
		return a
	}
	return b
}

func GetMapStrKeys(mapObj interface{}) ([]string, error) {
	keysMap := []string{}
	if InterfaceIsNil(mapObj) {
		return keysMap, nil
	}
	objV := reflect.Indirect(reflect.ValueOf(mapObj))
	if objV.Kind() != reflect.Map {
		return nil, errors.New("obj is not map type")
	}
	for _, keyV := range objV.MapKeys() {
		keysMap = append(keysMap, keyV.String())
	}
	return keysMap, nil
}

func InterfaceIsNil(val interface{}) (flag bool) {
	if !reflect.ValueOf(val).IsValid() {
		return true
	}
	if IsReferenceType(reflect.ValueOf(val)) && reflect.ValueOf(val).IsNil() {
		return true
	}
	return
}

func IsReferenceType(value reflect.Value) bool {
	switch value.Kind() {
	case reflect.Ptr, reflect.Chan, reflect.Interface, reflect.Func, reflect.Map, reflect.Slice:
		return true
	default:
		return false
	}
}

func GetRandomNum(minmum, maximum int) (result int, err error) {
	if maximum-minmum <= 0 {
		return 0, errors.New("maximum must larger than minimum")
	}
	rand.Seed(time.Now().UnixNano())
	return rand.Intn(maximum-minmum) + minmum, nil
}

func IsChClosed(ch chan struct{}) bool {
	_, ok := <-ch
	return ok
}
